package org.baeldung.common.web;
import java.util.List;
import javax.persistence.EntityNotFoundException;
import javax.validation.ConstraintViolationException;
import org.baeldung.common.persistence.exception.MyEntityNotFoundException;
import org.baeldung.common.web.exception.ApiError;
import org.baeldung.common.web.exception.MyConflictException;
import org.baeldung.common.web.exception.MyResourceNotFoundException;
import org.baeldung.common.web.exception.ValidationErrorDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.InvalidMediaTypeException;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.util.InvalidMimeTypeException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
private Logger log = LoggerFactory.getLogger(getClass());
public RestResponseEntityExceptionHandler() {
super();
}
// API
// 400
@Override
protected final ResponseEntity<Object> handleHttpMessageNotReadable(final HttpMessageNotReadableException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
log.info("Bad Request: {}", ex.getMessage());
log.debug("Bad Request: ", ex);
final ApiError apiError = message(HttpStatus.BAD_REQUEST, ex);
return handleExceptionInternal(ex, apiError, headers, HttpStatus.BAD_REQUEST, request);
}
@Override
protected final ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
log.info("Bad Request: {}", ex.getMessage());
log.debug("Bad Request: ", ex);
final BindingResult result = ex.getBindingResult();
final List<FieldError> fieldErrors = result.getFieldErrors();
final ValidationErrorDTO dto = processFieldErrors(fieldErrors);
return handleExceptionInternal(ex, dto, headers, HttpStatus.BAD_REQUEST, request);
}
@ExceptionHandler(value = { ConstraintViolationException.class, DataIntegrityViolationException.class })
public final ResponseEntity<Object> handleBadRequest(final RuntimeException ex, final WebRequest request) {
log.info("Bad Request: {}", ex.getLocalizedMessage());
log.debug("Bad Request: ", ex);
final ApiError apiError = message(HttpStatus.BAD_REQUEST, ex);
return handleExceptionInternal(ex, apiError, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
}
// 403
@ExceptionHandler({ AccessDeniedException.class })
public ResponseEntity<Object> handleEverything(final AccessDeniedException ex, final WebRequest request) {
logger.error("403 Status Code", ex);
final ApiError apiError = message(HttpStatus.FORBIDDEN, ex);
return handleExceptionInternal(ex, apiError, new HttpHeaders(), HttpStatus.FORBIDDEN, request);
}
// 404
@ExceptionHandler({ EntityNotFoundException.class, MyEntityNotFoundException.class, MyResourceNotFoundException.class })
protected ResponseEntity<Object> handleNotFound(final RuntimeException ex, final WebRequest request) {
log.warn("Not Found: {}", ex.getMessage());
final ApiError apiError = message(HttpStatus.NOT_FOUND, ex);
return handleExceptionInternal(ex, apiError, new HttpHeaders(), HttpStatus.NOT_FOUND, request);
}
// 409
@ExceptionHandler({ InvalidDataAccessApiUsageException.class, DataAccessException.class, MyConflictException.class })
protected ResponseEntity<Object> handleConflict(final RuntimeException ex, final WebRequest request) {
log.warn("Conflict: {}", ex.getMessage());
final ApiError apiError = message(HttpStatus.CONFLICT, ex);
return handleExceptionInternal(ex, apiError, new HttpHeaders(), HttpStatus.CONFLICT, request);
}
// 415
@ExceptionHandler({ InvalidMimeTypeException.class, InvalidMediaTypeException.class })
protected ResponseEntity<Object> handleInvalidMimeTypeException(final IllegalArgumentException ex, final WebRequest request) {
log.warn("Unsupported Media Type: {}", ex.getMessage());
final ApiError apiError = message(HttpStatus.UNSUPPORTED_MEDIA_TYPE, ex);
return handleExceptionInternal(ex, apiError, new HttpHeaders(), HttpStatus.UNSUPPORTED_MEDIA_TYPE, request);
}
// 500
@ExceptionHandler({ NullPointerException.class, IllegalArgumentException.class, IllegalStateException.class })
public ResponseEntity<Object> handle500s(final RuntimeException ex, final WebRequest request) {
logger.error("500 Status Code", ex);
final ApiError apiError = message(HttpStatus.INTERNAL_SERVER_ERROR, ex);
return handleExceptionInternal(ex, apiError, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
}
// UTIL
private ValidationErrorDTO processFieldErrors(final List<FieldError> fieldErrors) {
final ValidationErrorDTO dto = new ValidationErrorDTO();
for (final FieldError fieldError : fieldErrors) {
final String localizedErrorMessage = fieldError.getDefaultMessage();
dto.addFieldError(fieldError.getField(), localizedErrorMessage);
}
return dto;
}
private ApiError message(final HttpStatus httpStatus, final Exception ex) {
final String message = ex.getMessage() == null ? ex.getClass().getSimpleName() : ex.getMessage();
final String devMessage = ex.getClass().getSimpleName();
// devMessage = ExceptionUtils.getStackTrace(ex);
return new ApiError(httpStatus.value(), message, devMessage);
}
}